<?php

namespace App\Models;

use App\Constants\FileCategoryEnum;
use App\Constants\FileStatusEnum;
use App\Constants\FileTypeEnum;
use App\Constants\StorageTypeEnum;
use App\Constants\UploadStatusEnum;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;

/**
 * 文件模型
 * 管理系统中所有文件的元数据信息
 */
class File extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * 表名
     */
    protected $table = 'files';

    /**
     * 可填充字段
     */
    protected $fillable = [
        'user_id',
        'original_name',
        'file_name',
        'file_path',
        'file_size',
        'file_type',
        'mime_type',
        'file_hash',
        'storage_type',
        'file_category',
        'file_status',
        'upload_status',
        'upload_progress',
        'error_message',
        'metadata',
        'tags',
        'expires_at',
        'download_count',
        'last_downloaded_at',
        'version',
        'parent_id',
        'is_public',
        'access_token',
        'thumbnail_path',
        'preview_path',
        'width',
        'height',
        'duration',
        'pages',
        'encoding',
        'bitrate',
        'frame_rate',
        'resolution',
        'compression',
        'quality',
        'created_by',
        'updated_by',
    ];

    /**
     * 隐藏字段
     */
    protected $hidden = [
        'file_hash',
        'access_token',
        'deleted_at',
    ];

    /**
     * 字段类型转换
     */
    protected $casts = [
        'file_size' => 'integer',
        'file_hash' => 'string',
        'metadata' => 'array',
        'tags' => 'array',
        'expires_at' => 'datetime',
        'last_downloaded_at' => 'datetime',
        'version' => 'integer',
        'parent_id' => 'integer',
        'is_public' => 'boolean',
        'download_count' => 'integer',
        'upload_progress' => 'integer',
        'width' => 'integer',
        'height' => 'integer',
        'duration' => 'integer',
        'pages' => 'integer',
        'bitrate' => 'integer',
        'frame_rate' => 'decimal:2',
        'quality' => 'integer',
        'created_by' => 'integer',
        'updated_by' => 'integer',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * 日期字段
     */
    protected $dates = [
        'expires_at',
        'last_downloaded_at',
        'created_at',
        'updated_at',
        'deleted_at',
    ];

    // ============ 关联关系 ============

    /**
     * 关联用户（文件所有者）
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * 关联创建者
     */
    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * 关联更新者
     */
    public function updater(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    /**
     * 关联父文件（版本控制）
     */
    public function parent(): BelongsTo
    {
        return $this->belongsTo(self::class, 'parent_id');
    }

    /**
     * 关联子文件（版本控制）
     */
    public function children()
    {
        return $this->hasMany(self::class, 'parent_id');
    }

    // ============ 访问器 ============

    /**
     * 获取文件URL
     */
    public function getUrlAttribute(): string
    {
        return $this->getFileUrl();
    }

    /**
     * 获取缩略图URL
     */
    public function getThumbnailUrlAttribute(): ?string
    {
        if (!$this->thumbnail_path) {
            return null;
        }

        return $this->getStorageUrl($this->thumbnail_path);
    }

    /**
     * 获取预览URL
     */
    public function getPreviewUrlAttribute(): ?string
    {
        if (!$this->preview_path) {
            return null;
        }

        return $this->getStorageUrl($this->preview_path);
    }

    /**
     * 获取文件大小格式化字符串
     */
    public function getFormattedSizeAttribute(): string
    {
        return $this->formatFileSize($this->file_size);
    }

    /**
     * 获取文件类型标签
     */
    public function getFileTypeLabelAttribute(): string
    {
        return FileTypeEnum::getLabels()[$this->file_type] ?? $this->file_type;
    }

    /**
     * 获取文件状态标签
     */
    public function getFileStatusLabelAttribute(): string
    {
        return FileStatusEnum::getLabels()[$this->file_status] ?? $this->file_status;
    }

    /**
     * 获取存储类型标签
     */
    public function getStorageTypeLabelAttribute(): string
    {
        return StorageTypeEnum::getLabels()[$this->storage_type] ?? $this->storage_type;
    }

    /**
     * 获取文件分类标签
     */
    public function getFileCategoryLabelAttribute(): string
    {
        return FileCategoryEnum::getLabels()[$this->file_category] ?? $this->file_category;
    }

    /**
     * 获取上传状态标签
     */
    public function getUploadStatusLabelAttribute(): string
    {
        return UploadStatusEnum::getLabels()[$this->upload_status] ?? $this->upload_status;
    }

    /**
     * 检查文件是否已过期
     */
    public function getIsExpiredAttribute(): bool
    {
        return $this->expires_at && $this->expires_at->isPast();
    }

    /**
     * 检查文件是否可预览
     */
    public function getIsPreviewableAttribute(): bool
    {
        return FileTypeEnum::isPreviewable($this->file_type);
    }

    /**
     * 检查文件是否为图片
     */
    public function getIsImageAttribute(): bool
    {
        return FileTypeEnum::isImage($this->file_type);
    }

    /**
     * 检查文件是否为视频
     */
    public function getIsVideoAttribute(): bool
    {
        return in_array($this->file_type, [FileTypeEnum::MP4, FileTypeEnum::AVI, FileTypeEnum::MOV, FileTypeEnum::WMV, FileTypeEnum::FLV, FileTypeEnum::WEBM, FileTypeEnum::MKV]);
    }

    /**
     * 检查文件是否为音频
     */
    public function getIsAudioAttribute(): bool
    {
        return in_array($this->file_type, [FileTypeEnum::MP3, FileTypeEnum::WAV, FileTypeEnum::FLAC, FileTypeEnum::AAC, FileTypeEnum::OGG]);
    }

    /**
     * 检查文件是否为文档
     */
    public function getIsDocumentAttribute(): bool
    {
        return FileTypeEnum::isDocument($this->file_type) || FileTypeEnum::isOffice($this->file_type);
    }

    // ============ 作用域 ============

    /**
     * 活跃文件作用域
     */
    public function scopeActive($query)
    {
        return $query->where('file_status', FileStatusEnum::ACTIVE);
    }

    /**
     * 公开文件作用域
     */
    public function scopePublic($query)
    {
        return $query->where('is_public', true);
    }

    /**
     * 私有文件作用域
     */
    public function scopePrivate($query)
    {
        return $query->where('is_public', false);
    }

    /**
     * 按用户过滤作用域
     */
    public function scopeByUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }

    /**
     * 按文件类型过滤作用域
     */
    public function scopeByType($query, $fileType)
    {
        return $query->where('file_type', $fileType);
    }

    /**
     * 按文件分类过滤作用域
     */
    public function scopeByCategory($query, $category)
    {
        return $query->where('file_category', $category);
    }

    /**
     * 按存储类型过滤作用域
     */
    public function scopeByStorage($query, $storageType)
    {
        return $query->where('storage_type', $storageType);
    }

    /**
     * 未过期文件作用域
     */
    public function scopeNotExpired($query)
    {
        return $query->where(function ($q) {
            $q->whereNull('expires_at')
              ->orWhere('expires_at', '>', now());
        });
    }

    /**
     * 过期文件作用域
     */
    public function scopeExpired($query)
    {
        return $query->where('expires_at', '<=', now());
    }

    // ============ 业务方法 ============

    /**
     * 获取文件URL
     */
    public function getFileUrl(): string
    {
        return $this->getStorageUrl($this->file_path);
    }

    /**
     * 获取存储URL
     */
    protected function getStorageUrl(string $path): string
    {
        // 根据存储类型生成不同的URL
        switch ($this->storage_type) {
            case StorageTypeEnum::LOCAL:
                return asset('storage/' . $path);

            case StorageTypeEnum::AWS_S3:
            case StorageTypeEnum::ALICLOUD_OSS:
            case StorageTypeEnum::TENCENT_COS:
            case StorageTypeEnum::QINIU_KODO:
            case StorageTypeEnum::BAIDU_BOS:
            case StorageTypeEnum::CLOUDFLARE_R2:
                // 云存储URL生成逻辑
                return $this->getCloudStorageUrl($path);

            case StorageTypeEnum::CDN:
                // CDN URL生成逻辑
                return config('filesystems.disks.cdn.url') . '/' . $path;

            default:
                return asset('storage/' . $path);
        }
    }

    /**
     * 获取云存储URL
     */
    protected function getCloudStorageUrl(string $path): string
    {
        $disk = config('filesystems.disks.' . $this->storage_type);

        if (!$disk) {
            return asset('storage/' . $path);
        }

        // 生成带签名的URL（如果需要）
        if ($this->requiresSignedUrl()) {
            return Storage::disk($this->storage_type)->temporaryUrl(
                $path,
                now()->addMinutes(60)
            );
        }

        return Storage::disk($this->storage_type)->url($path);
    }

    /**
     * 检查是否需要签名URL
     */
    protected function requiresSignedUrl(): bool
    {
        // 私有文件需要签名URL
        return !$this->is_public;
    }

    /**
     * 格式化文件大小
     */
    public static function formatFileSize(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];

        for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
            $bytes /= 1024;
        }

        return round($bytes, 2) . ' ' . $units[$i];
    }

    /**
     * 增加下载计数
     */
    public function incrementDownloadCount(): void
    {
        $this->increment('download_count');
        $this->update(['last_downloaded_at' => now()]);
    }

    /**
     * 检查文件是否存在
     */
    public function exists(): bool
    {
        return Storage::disk($this->storage_type)->exists($this->file_path);
    }

    /**
     * 删除物理文件
     */
    public function deleteFile(): bool
    {
        if ($this->exists()) {
            return Storage::disk($this->storage_type)->delete($this->file_path);
        }

        return true;
    }

    /**
     * 复制文件
     */
    public function copyTo(string $newPath): bool
    {
        return Storage::disk($this->storage_type)->copy($this->file_path, $newPath);
    }

    /**
     * 移动文件
     */
    public function moveTo(string $newPath): bool
    {
        return Storage::disk($this->storage_type)->move($this->file_path, $newPath);
    }

    /**
     * 获取文件内容
     */
    public function getContent(): string
    {
        return Storage::disk($this->storage_type)->get($this->file_path);
    }

    /**
     * 更新文件状态
     */
    public function updateStatus(string $status, ?string $uploadStatus = null): bool
    {
        $data = ['file_status' => $status];

        if ($uploadStatus) {
            $data['upload_status'] = $uploadStatus;
        }

        return $this->update($data);
    }

    /**
     * 创建新版本
     */
    public function createVersion(string $newPath, string $newName): self
    {
        $version = $this->children()->max('version') ?? 0;

        return self::create([
            'user_id' => $this->user_id,
            'original_name' => $newName,
            'file_name' => basename($newPath),
            'file_path' => $newPath,
            'file_size' => $this->file_size,
            'file_type' => $this->file_type,
            'mime_type' => $this->mime_type,
            'file_hash' => $this->file_hash,
            'storage_type' => $this->storage_type,
            'file_category' => $this->file_category,
            'file_status' => FileStatusEnum::ACTIVE,
            'upload_status' => UploadStatusEnum::COMPLETED,
            'version' => $version + 1,
            'parent_id' => $this->id,
            'is_public' => $this->is_public,
            'created_by' => auth()->id(),
        ]);
    }

    /**
     * 获取文件统计信息
     */
    public function getStatistics(): array
    {
        return [
            'total_versions' => $this->children()->count() + 1,
            'total_downloads' => $this->download_count,
            'last_download' => $this->last_downloaded_at?->diffForHumans(),
            'file_age' => $this->created_at->diffForHumans(),
            'is_expired' => $this->is_expired,
            'storage_used' => self::formatFileSize($this->file_size),
        ];
    }

    // ============ 模型事件 ============

    /**
     * 模型删除事件
     */
    protected static function booted(): void
    {
        static::deleting(function (File $file) {
            // 删除物理文件
            $file->deleteFile();

            // 删除缩略图和预览文件
            if ($file->thumbnail_path) {
                Storage::disk($file->storage_type)->delete($file->thumbnail_path);
            }

            if ($file->preview_path) {
                Storage::disk($file->storage_type)->delete($file->preview_path);
            }
        });

        static::updating(function (File $file) {
            // 记录更新者
            if (auth()->check()) {
                $file->updated_by = auth()->id();
            }
        });
    }
}
